package cn.pupil.springframework.core.convert.converter;

import cn.hutool.core.lang.Assert;

import java.util.Objects;
import java.util.Set;

/**
 * @Description: 通用转换器接口
 * @Author: pupil
 * @Date: 2024/12/16 下午 4:39
 */
public interface GenericConverter {

    /**
     * Return the source and target types that this converter can convert between.
     * 返回此转换器可以在其间转换的源类型和目标类型。
     */
    Set<ConvertiblePair> getConvertibleTypes();

    /**
     * Convert the source object to the targetType described by the {@code TypeDescriptor}.
     * 将源对象转换为由｛@code TypeDescriptor｝描述的targetType。
     *
     * @param source     the source object to convert (may be {@code null}) 要转换的源对象（可以是{@code null}）
     * @param sourceType the type descriptor of the field we are converting from 我们正在转换的字段的类型描述符
     * @param targetType the type descriptor of the field we are converting to 我们正在转换为的字段的类型描述符
     * @return the converted object 转换后的对象
     */
    Object convert(Object source, Class sourceType, Class targetType);

    /**
     * Holder for a source-to-target class pair.
     * 可转换的源/目标类型对
     */
    final class ConvertiblePair {
        private final Class<?> sourceType;

        private final Class<?> targetType;

        public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
            Assert.notNull(sourceType, "Source type must not be null");
            Assert.notNull(targetType, "Target type must not be null");
            this.sourceType = sourceType;
            this.targetType = targetType;
        }

        public Class<?> getSourceType() {
            return sourceType;
        }

        public Class<?> getTargetType() {
            return targetType;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ConvertiblePair that = (ConvertiblePair) o;
            return Objects.equals(sourceType, that.sourceType) && Objects.equals(targetType, that.targetType);
        }

        @Override
        public int hashCode() {
            return this.sourceType.hashCode() * 31 + this.targetType.hashCode();
        }
    }
}
